/*
 *  Copyright (C) 2010:
 *                 Buzzanca Marco <marco.bzn@gmail.com>
 *         Monaco Davide Giuseppe <black.ralkass@gmail.com>
 *              Petralia Veronica <veronicapetralia@gmail.com>
 *
 * This file is part of DS2011BMP
 *
 * DS2011BMP is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * DS2011BMP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

/**
 * @file worker.h
 * @author Marco Buzzanca
 * @author Davide Giuseppe Monaco
 *
 * This file contains Worker class implementation.
 */
#include "worker.h"

Worker::Worker(boost::uint16_t port)
  : _tqm(port), _file_server(15000) { }

Worker::~Worker() { }

void Worker::run(void)
{
    for (int i = 0; i < 1; i++)
        _workers.add_thread(new boost::thread(&Worker::serve, this, i));

    _tqm.start();

    // Technically never reached
    _workers.join_all();
}

void Worker::serve(int id)
{
    ui_proxy_t proxy = _uipf.getProxy();

    _file_server.bind();

    for (;;)
    {
        TaskDescriptor td = _tqm.dequeue();

        std::cout << "(" << id << ") Original: " << td.getLink() << " " << td.getCommand() << std::endl;

        std::string local_file = proxy->getFile(td.getLink());

        td.setLink(local_file);

        std::stringstream ss(td.getCommand());
        std::string args;

        // Ignores executable path and gets arguments string
        ss.ignore(std::numeric_limits<std::streamsize>::max(), ' ');
        getline(ss, args);

        td.setCommand(local_file + " " + args);

        std::cout << "(" << id << ") Modified: " << td.getLink() << " " << td.getCommand() << std::endl;

        // This should be technically part of UIProxy
        _file_server.receiveFile(local_file.c_str());

        // Unfortunately boost doesn't allow cross-platform permission settings.
        // This doesn't work on windows.
        #ifndef _WIN32
            chmod(local_file.c_str(), 0777);
        #endif

        std::cout << "Exec" << std::endl;
    }
}

int Worker::exec(const TaskDescriptor& val)
{
  std::cout << "Worker: attemping to execute " << val.getCommand() << std::endl;

  // stringstream used to tokenize TaskDescriptor's command string
  std::stringstream ss(val.getCommand());

  std::string buf;
  std::vector<std::string> tokens;

  // string.split(" ") equivalent
  while (ss >> buf)
    tokens.push_back(buf);

  // create argv for execve()
  char *argv[tokens.size() + 1];

  for (size_t i = 0; i < tokens.size(); i++) {
    argv[i] = new char(tokens[i].length());
    strncpy(argv[i], tokens[i].c_str(), tokens[i].length());
  }

  argv[tokens.size()] = NULL;

  pid_t p = fork();

  if (p == 0) {
    // dummy envp
    char *envp[] = { NULL };

    if (execve(argv[0], argv, envp) == -1)
      std::cerr << "Error during task execution" << std::endl;
  }

  for (size_t i = 0; i < tokens.size(); i++)
    delete argv[i];

  return 0;
}
